package com.itclass.queue;

import com.itclass.lock.CustomizeAbstractQueuedSynchronizer;

import java.lang.invoke.VarHandle;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @param <E>
 */

public class CasMaxPriorityArrayBlockingQueue<E> extends AbstractPriorityArrayBlockingQueue<E> {


    private final CasConditionObject notEmpty = new CasConditionObject();

    public CasMaxPriorityArrayBlockingQueue(List<Integer> priority) {
        super(priority.get(priority.size() - 1));
        for (int i = 0; i < queue.length; i++) {
            RootNode<E> node = new RootNode<>(null);
            node.prev = node;
            node.next = node;
            queue[i] = node;
        }
    }

    public CasMaxPriorityArrayBlockingQueue() {
        super();
        for (int i = 0; i < queue.length; i++) {
            RootNode<E> node = new RootNode<>(null);
            node.prev = node;
            node.next = node;
            queue[i] = node;
        }
    }

    @Override
    public Iterator<E> iterator() {
        return null;
    }

    @Override
    protected int getPriority(E e) {
        if (e instanceof PriorityTask) {
            PriorityTask priorityTask = (PriorityTask) e;
            return priorityTask.getPriority();
        }
        return 0;
    }


    @Override
    protected boolean doOffer(E e) {
        // 获取
        int index = getPriority(e);

        // 判断队列索引是否超过队列大小
        if (index > getQueueSize()) {
            throw new ArrayIndexOutOfBoundsException("queue size " + getQueueSize() + " task queue index " + index);
        }

        // 创建节点
        Node<E> node = new Node<>(e);
        // 获取头节点
        RootNode<E> head = (RootNode<E>) queue[index];

        if (size() >= capacity)
            return false;
        // 入队
        return enqueue(head, node);
    }

    /**
     * 取元素
     *
     * @param await
     * @return
     * @throws InterruptedException
     */
    @Override
    protected E doPoll(boolean await) throws InterruptedException {


        E result = null;
        restart:
        do {
            for (int i = queue.length - 1; i >= 0; i--) {
                RootNode<E> headNode = (RootNode<E>) queue[i];

                // 证明是头节点跳过
                if (headNode.size() == 0 || headNode == headNode.prev) continue;

                result = dequeue(headNode);

                if (result != null) {
                    break restart;
                }
            }

            /**
             * 代码执行到这样，证明队列没有元素了判断是否线程需要等待？还是 直接返回 ？
             */
            if (!await) break;

            // 如果容量为0 等待
            notEmpty.await();

        } while (size() == 0 && await);

        return result;
    }

    @Override
    protected E doTake() throws InterruptedException {
        return doPoll(true);
    }

    /**
     * 出队
     *
     * @param rootNode
     * @return
     */
    private E dequeue(RootNode<E> rootNode) {

        Node<E> tailNode = rootNode.prev;

        while (rootNode.size() > 0) {

            // 证明是头节点了，退出cas
            if (rootNode == tailNode) return null;

            // 新的尾部节点
            Node<E> newTail = tailNode.prev;

            E item =null;

            if ((item = tailNode.item) != null) {
                // 设置新的尾节点
                if (NODE_PREV_HANDLE.compareAndSet(rootNode, tailNode, newTail)) {
                    newTail.next = rootNode;  // 维护 next 指针
                    tailNode.item = null;
                    tailNode.next = null;
                    tailNode.prev = null;
                    rootNode.getAndDecrement();
                    return item;
                }
            } else if (item == null) {
                System.out.println("item = " + item);
            } else {
                // 自旋等待下
                Thread.onSpinWait();
            }

        }
        return null;
    }

    /**
     * 入队
     *
     * @param head
     * @param node
     * @return
     */

    private boolean enqueue(RootNode<E> head, Node<E> node) {

        boolean result = false;
        do {
            // 头节点下一个元素
            Node<E> next = head.next;
            node.next = next;
            node.prev = head;
            // 尝试将新节点插入链表
            if (NODE_NEXT_HANDLE.compareAndSet(head, next, node)) {
                next.prev = node;
                // 队列+1 返回上一个数字
                int c = head.getAndIncrement();
                // 数量+1
                if (c + 1 < capacity) {
                    //  添加成功 唤醒线程
                    notEmpty.signal();
                }

                result = true;
                break;
            } else {
                // 自旋等待下
                Thread.onSpinWait();
            }
        } while (size() < capacity);

        return result;
    }

    public int size() {
        int size = 0;
        for (int i = 0; i < queue.length; i++) {
            RootNode<E> node = (RootNode<E>) queue[i];
            size += node.size();
        }
        return size;
    }
    @Override
    public void put(E e) throws InterruptedException {

    }

    @Override
    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public E take() throws InterruptedException {
        return doTake();
    }

    @Override
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        return null;
    }

    @Override
    public int remainingCapacity() {
        return 0;
    }

    @Override
    public int drainTo(Collection<? super E> c) {
        return 0;
    }

    @Override
    public int drainTo(Collection<? super E> c, int maxElements) {
        return 0;
    }

    @Override
    public E peek() {
        return null;
    }

      class RootNode<E> extends Node<E> {

        // 队列数量
        protected final AtomicInteger count = new AtomicInteger();

        RootNode(E x) {
            super(x);
        }

        /**
         * +1
         * @return
         */
        public int getAndIncrement() {
            return count.getAndIncrement();
        }

        /**
         * -1
         * @return
         */
        public int getAndDecrement() {
            return count.getAndDecrement();
        }

        public int size() {
            return count.get();
        }

    }

}
